// TODO: query for registers
class Engine {
  Map asm_ = const {
    '6502': Asm6502
  };

  IAsm current_asm_ = null;

  Map labels_ = {};

  List<String> code_ = null;

  DivElement register_view_ = null;

  int current_line_ = -1;

  var timeout_ = null;

  void initialize(String current_asm, this.register_view_)
      : current_asm_ = asm_[current_asm],
        code_ = null,
        current_line_ = 0 {
    current_asm_.initialize();
    current_asm_.updateRegisterView(register_view_);
  }

  void reset() {
    timeout_ = null;
    current_line_ = -1;
    register_view_ = null;
    code_ = null;
    labels_ = {};
  }

  void setReturnHere() {
    labels_['return'] = current_line_;
  }

  void jumpToLabel(String label) {
    current_line_ = labels_[label];
  }

  void runToStart(List<String> code) {
    code_ = code;
    for (int i = 0; i < code_.length; ++i)
      if (code_[i].match(/^\./) !== null)
        labels_[code_[i].substr(1)] = i;

    current_line_ = 0;
    if (labels_['start'] !== undefined)
      jumpToLabel('start');
  }

  int run() {
    int time_taken = step();
    if (time_taken === -1) {
      window.clearTimeout(timeout_);
      return -1;
    }

    timeout_ = window.setTimeout(run, timeTaken);
    return timeTaken;
  }

  void pause() {
    window.clearTimeout(timeout_);
  }

  int step() {
    String line = code_[current_line_];
    
    // Skip labels
    // TODO: Skip comments and blank lines
    while (line.match(/^\./) !== null) {
      ++current_line_;
      line = code_[current_line_];
      if (line === undefined) {
        print('COMPLETE');
        return -1;
      }
    }

    String instruction = line.split(' ')[0];
    print('Executing $line');

    var op = current_asm_.instruction_map_[instruction];
    if (op === undefined || op === null) {
      print('ERROR: Unknown instruction "$instruction"');
      return -1;
    }

    try {
      int time_taken = op(line.split(' ')[1];
      current_asm_.updateRegisterView(register_view_);

      // Queue up the next instruction
      // TODO: skip comments, blank lines and branch labels
      ++current_line_;

      if (code_[current_line_] === undefined) {
        print('COMPLETE');
        return -1;
      }

      return time_taken;
    } catch (e) {
      if (e.stack)
        print(e.stack);
      else if (e.message)
        print(e.message);
      else
        print(e);
      return -1;
    }
  }
}
